package grpc_proxy_middleware

import (
	"context"
	"gitee.com/zhoulvvv/my_go_gateway/dao"
	"gitee.com/zhoulvvv/my_go_gateway/public"
	"gitee.com/zhoulvvv/my_go_gateway/services"
	"github.com/pkg/errors"
	"google.golang.org/grpc"
	"google.golang.org/grpc/metadata"
	"log"
	"strings"
)

type wrappedStream struct {
	grpc.ServerStream
	ctx context.Context
}

func (s *wrappedStream) Context() context.Context {
	return s.ctx
}

// grpc token 校验中间件
func GRPCJwtOAuthTokenModeMiddleware(service *dao.ServiceDetail) func(srv interface{}, ss grpc.ServerStream,
	info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
	return func(srv interface{}, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
		md, ok := metadata.FromIncomingContext(ss.Context())
		if !ok {
			log.Printf("【GRPC token 校验中间件】 failed with error metadata.FromIncomingContext(ss.Context())")
		}
		// 判断是否开启了权限校验
		if service.AccessControl.OpenAuth == 1 {
			// 0、从请求头中获取token信息
			auths := md.Get("Authorization")
			// Bearer token
			token := strings.ReplaceAll(auths[0], "Bearer ", "")
			log.Printf("【grpc】token校验中间件：%s\n", token)
			if token == "" {
				return errors.New("【grpc】没有权限访问该接口")
			}
			// 1、解密token
			claims, err := public.JwtDecode(token)
			log.Printf("【grpc】token解密信息：%s\n", public.ObjToJson(claims))
			if err != nil {
				return errors.New("【grpc】校验token中间件中解析token失败：" + err.Error())
			}
			// 2、获取到app_id，在根据app_id得到app信息
			appId := claims.Issuer
			appList := services.AppManagerHandler.GetAppList()
			appFlag := false
			for _, item := range appList {
				if item.AppId == appId {
					// 3、把app信息放入到metadata的上下文中
					md.Set("app", public.ObjToJson(item))
					appFlag = true
					break
				}
			}
			if !appFlag {
				return errors.New("【grpc】没有匹配到对应的用户信息")
			}
		}
		ctx := metadata.NewIncomingContext(ss.Context(), md)
		if err := handler(srv, &wrappedStream{ss, ctx}); err != nil {
			log.Printf("【GRPC】RPC failed with error %v\n", err)
		}
		return nil
	}
}
